package main

import (
	"encoding/binary"
	"errors"
	"log"
	"net"

	//"net/http"
	"bytes"
	"crypto/md5"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

const BUF_SIZE int32 = 65536
const MAX_ERROR_MSG_SIZE int32 = 512
const MAX_PREPARE_STMT_SIZE = 65536 * 2 /*最大的Prepare的SQL长度，超过了此长度，会报错 */

type PgFrontConn struct {
	Conn           net.Conn
	Pid            uint32
	BackendKeyData uint32
}

var g_next_pid uint32 = 1000

type PgBackendConn struct {
	Id               int32
	Conn             net.Conn
	State            int32
	nextPrepareId    int32
	needClosePrepare []int32
	ReConnCnt        int32 //重连接次数，每重新连接一次时，此次数加1
	Lock             sync.Mutex
	dbConf           *DbConfig
	LastFrontId      uint32 //最后使用这个后端的前端ID
}

func (p *PgBackendConn) AllocPrepareId() int32 {
	var ret int32
	//FIXME: 是否会溢出？
	ret = atomic.AddInt32(&p.nextPrepareId, 1)
	return ret
}

func (p *PgBackendConn) DeletePrepareId(prepareId int32) {
	p.Lock.Lock()
	defer p.Lock.Unlock()
	p.needClosePrepare = append(p.needClosePrepare, prepareId)
}

type PrepareIdData struct {
	PrepareId      int32
	PrepareRequest []byte
}

type PrepareInBackend struct {
	PrepareId int32
	BackConn  *PgBackendConn
	ReConnCnt int32 //记录着当时完成prepare时后端连接的重连次数，如果后端重新连接之后，后端连接上的重连次数就会加1，这时就与此值不相同的，这样就知道了此连接被重新连接过
}

func (p *PrepareInBackend) DeletePrepare() {
	p.BackConn.DeletePrepareId(p.PrepareId)
}

type PrepareData struct {
	PrepareRequest []byte /*发到后端的prepare数据*/
	BackendMap     map[int32]*PrepareInBackend
}

/* 记录一个前端连接过来的prepare数据 */
type CachedPrepare struct {
	mp map[string]*PrepareData
}

func (p *CachedPrepare) Init() {
	p.mp = make(map[string]*PrepareData)
}

func (p *CachedPrepare) Get(prepareName string) (*PrepareData, bool) {
	d, ok := p.mp[prepareName]
	return d, ok
}

func (p *CachedPrepare) AddPrepare(prepareName string, prepareData *PrepareData) {
	p.mp[prepareName] = prepareData
}

func (p *CachedPrepare) DeletePrepare(prepareName string) {
	prepareData, ok := p.mp[prepareName]
	if !ok {
		return
	}

	for _, prepareInBackend := range prepareData.BackendMap {
		prepareInBackend.DeletePrepare()
	}
	delete(p.mp, prepareName)
}

func (p *CachedPrepare) Discard() {
	for _, v := range p.mp {
		for _, prepareInBackend := range v.BackendMap {
			prepareInBackend.DeletePrepare()
		}
	}
	p.mp = nil
}

var g_backend_pool = make(map[string][]*PgBackendConn, 1)

func appendString(buf []byte, str string) int32 {
	n := copy(buf, str)
	buf[n] = 0
	return int32(n + 1)
}

/*
读取一个PG的数据包，返回三个值，
	第1个值为读取的字节数，
	第2值为还需要读取的字节数，这通常是数据包比较大，在buf中放不下的情况，
	第3值是错误
*/
func recvMessage(conn net.Conn, buf []byte) (int32, int32, error) {
	var ret int
	var err error
	var pos int32 = 0
	var dataLen int32
	var endPos int32

	bufSize := int32(len(buf))

	//log.Printf("Enter recvMessage\n")
	//defer log.Printf("Leave recvMessage\n")

	for {
		//log.Printf("Being read ...\n")
		ret, err = conn.Read(buf[pos:5])
		//log.Printf("conn.Read return: ret=%d\n", ret)
		if err != nil {
			conn.Close()
			return pos, 0, err
		}
		pos += int32(ret)
		if pos < 5 {
			continue
		}
		break
	}

	dataLen = int32(binary.BigEndian.Uint32(buf[1:5]))
	if dataLen > bufSize-1 {
		endPos = bufSize
	} else {
		endPos = dataLen + 1
	}

	//log.Printf("dataLen=%d\n", dataLen);

	for {
		ret, err = conn.Read(buf[pos:endPos])
		if err != nil {
			conn.Close()
			return pos, 0, err
		}
		pos += int32(ret)
		if pos >= endPos {
			break
		}
	}

	if dataLen+1 > bufSize {
		return pos, dataLen + 1 - bufSize, nil
	} else {
		return pos, 0, nil
	}
}

func recvData(conn net.Conn, buf []byte, dataLen int) error {
	var pos = 0
	var ret int
	var err error

	for {
		ret, err = conn.Read(buf[pos:dataLen])
		if err != nil {
			conn.Close()
			return err
		}
		pos += ret
		if pos >= dataLen {
			break
		}
	}
	return nil
}

func sendData(conn net.Conn, buf []byte) (int32, error) {
	var pos int32 = 0
	var ret int
	var err error
	var sendLen = int32(len(buf))

	for pos < sendLen {
		ret, err = conn.Write(buf[pos:sendLen])
		if err != nil {
			log.Printf("Send data error: %s\n", err.Error())
			conn.Close()
			return pos, err
		}
		pos += int32(ret)
	}
	return pos, nil
}

/*
转发数据的函数
*/
func transData(srcConn net.Conn, dstConn net.Conn, dataLen int32, buf []byte) (error, bool) {
	var err error
	var ret int
	var oprSize int32
	var pos int32
	var sendLen int32
	var leftSize = dataLen

	for leftSize > 0 {
		if leftSize > BUF_SIZE {
			oprSize = BUF_SIZE
		} else {
			oprSize = leftSize
		}
		ret, err = srcConn.Read(buf[0:oprSize])
		if err != nil {
			return err, true
		}

		sendLen = int32(ret)
		pos = 0
		for pos < sendLen {
			ret, err = dstConn.Write(buf[pos:sendLen])
			if err != nil {
				return err, false
			}
			pos += int32(ret)
		}
		leftSize -= sendLen
	}
	return nil, false
}

/*PG的md5的计算
 * concat('md5', md5(concat(md5(concat(password, username)), random-salt)))
 */

func md5AuthCalc(buf []byte, user string, password string, salt []byte) {
	var tmpbuf [256]byte
	var pos int32
	var n int32

	//把dstBuf中先拷贝入“md5”
	copy(buf, []byte("md5"))

	// 先把password和user拼接到tmpbuf中
	pos = int32(copy(tmpbuf[0:], []byte(password)))
	n = int32(copy(tmpbuf[pos:], []byte(user)))
	pos += n

	// 把password和user拼接的结果做一次md5运算，结果仍然放到tmpbuf中
	h := md5.New()
	h.Write(tmpbuf[:pos])
	hex.Encode(tmpbuf[0:], h.Sum(nil))

	// 把第一次md5的结果与salt进行拼接
	n = int32(copy(tmpbuf[32:], salt[:4]))
	// 进行第二次md5运算
	h = md5.New()
	h.Write(tmpbuf[:32+n])
	hex.Encode(buf[3:], h.Sum(nil))
}

/*
* 解析key/value的消息内容ParameterStatus消息
 */

func parseKeyValuePacket(buf []byte) (string, string) {
	var i uint32
	var isValue = false
	var dataLen = binary.BigEndian.Uint32(buf[0:4])
	var begin uint32
	var key = ""
	var value = ""

	begin = 4
	i = 4
	for i < dataLen {
		if buf[i] == 0 {
			if !isValue {
				key = string(buf[begin:i])
				isValue = true
			} else {
				value = string(buf[begin:i])
				return key, value
			}
			begin = i + 1
		}
		i++
	}
	return key, value
}

func connectBackend(dbConf *DbConfig) (net.Conn, error) {
	var conn net.Conn
	var err error
	var n int32
	var buf []byte
	var pos int32
	//var leftLen int32

	buf = make([]byte, 2048)
	var portal = dbConf.getNextPortal()
	d := net.Dialer{Timeout: 10 * time.Second}
	conn, err = d.Dial("tcp", portal)
	if err != nil {
		log.Printf("Could not connect to %s: %s", portal, err.Error())
		return nil, err
	}

	//pos = 4
	//binary.BigEndian.PutUint16(recvBuf[pos:], 3)
	//pos += 2
	//binary.BigEndian.PutUint32(recvBuf[5:], 0)
	//pos += 2

	pos = 8

	connOpts := map[string]string{
		"user":             dbConf.User,
		"database":         dbConf.Dbname,
		"client_encoding":  "UTF8",
		"application_name": "src",
	}

	for key, value := range connOpts {
		pos += appendString(buf[pos:], key)
		pos += appendString(buf[pos:], value)
	}
	buf[pos] = 0
	pos++
	//填包长度
	binary.BigEndian.PutUint32(buf[0:], uint32(pos))
	//填版本号，为3.0版本
	binary.BigEndian.PutUint16(buf[4:], 3)
	binary.BigEndian.PutUint16(buf[6:], 0)

	_, err = sendData(conn, buf[0:pos])
	if err != nil {
		log.Printf("Send to db error: %s\n", err.Error())
		conn.Close()
		return nil, err
	}

	n, _, err = recvMessage(conn, buf[0:])
	if err != nil {
		log.Printf("Recv from db error: %s\n", err.Error())
		conn.Close()
		return nil, err
	}

	if buf[0] != 'R' {
		log.Printf("Expect from db recv 'R' message, but recv %c message: %v\n", buf[0], string(buf))
		conn.Close()
		return nil, errors.New("receive invalid packet")
	}
	authType := binary.BigEndian.Uint32(buf[5:])
	if authType == 5 { /*type = 5 为md5验证*/

		/* concat('md5', md5(concat(md5(concat(password, username)), random-salt))) */

		md5AuthCalc(buf[5:], dbConf.User, dbConf.Passwd, buf[9:13])
		buf[0] = 'p'
		buf[40] = 0
		binary.BigEndian.PutUint32(buf[1:], 40)
		n, err = sendData(conn, buf[:41])
		if err != nil {
			log.Printf("Send to DbConfig error: %s\n", err.Error())
			conn.Close()
			return nil, err
		}
	} else if authType == 0 { /*type = 0 为trust验证, 代表连接成功不需要做处理*/

	} else {
		log.Printf("Only support md5(type=5) and trust(type=0), can not support type = %d\n", authType)
		conn.Close()
		return nil, errors.New("only support md5(type=5)")
	}

	for {
		n, _, err = recvMessage(conn, buf[:])
		if err != nil {
			log.Printf("Recv from DbConfig error: %s\n", err.Error())
			conn.Close()
			return nil, err
		}
		if buf[0] == 'S' {
			//key, value := parseKeyValuePacket(recvBuf[1:])
			parseKeyValuePacket(buf[1:])
			//log.Printf("Recv from DbConfig parameter: %s=%s\n", key, value)
		} else if buf[0] == 'E' {
			n = int32(binary.BigEndian.Uint32(buf[1:]))
			log.Printf("Recv from DbConfig Error: %s\n", string(buf[5:n-1]))
		} else if buf[0] == 'Z' { /* ReadyForQuery */
			//log.Printf("Recv from DbConfig ReadyForQuery, trans status is %c\n", recvBuf[5])
			break
		} else {
			//log.Printf("Unknown message type: %c, msg length: %d", recvBuf[0], n)
		}
	}
	return conn, nil
}

func (p *PgBackendConn) Reconnect() {
	var err error
	var retryCnt = 0
	p.Conn.Close()
	for {
		p.Conn, err = connectBackend(p.dbConf)
		if err == nil {
			break
		}
		retryCnt++
		log.Printf("Could not connect: %s", err.Error())
		if retryCnt > 0 {
			if retryCnt > 10 {
				time.Sleep(10 * time.Second)
			} else {
				time.Sleep(time.Duration(retryCnt) * time.Second)
			}
		}
	}
	p.ReConnCnt++
}

/*
接收启动包，注意启动包没有类型字段（即第一个字节）
*/
func recvStartupPacket(conn net.Conn, buf []byte) (int32, error) {
	var ret int
	var err error
	var pos int32 = 0
	var dataLen int32

	for pos < 4 {
		ret, err = conn.Read(buf[pos:4])
		if err != nil {
			conn.Close()
			return 0, err
		}
		pos += int32(ret)
	}

	dataLen = int32(binary.BigEndian.Uint32(buf[0:4]))
	for pos < dataLen {
		ret, err = conn.Read(buf[pos:dataLen])
		if err != nil {
			log.Printf("Recv from client error(in recvStartupPacket) : %s\n", err.Error())
			conn.Close()
			return 0, err
		}
		pos += int32(ret)
	}
	return pos, nil
}

/*
 * 解析多个key/value对的内容，如启动消息中的内容，就是由多对key/value，结束时有两个\0\0
 */
func parseMulKeyValuePacket(buf []byte, dataLen int32) map[string]string {
	kvs := make(map[string]string)

	var i int32 = 0
	var begin = i
	var isValue = false
	var key string

	for i < dataLen {
		if buf[i] == 0 {
			if !isValue {
				key = string(buf[begin:i])
				isValue = true
			} else {
				kvs[key] = string(buf[begin:i])
				isValue = false
				//log.Printf("%s=%s\n", key, kvs[key])
			}
			begin = i + 1
			if i < dataLen-1 {
				/* 如果后面连续有两个0，则认为是结束*/
				if buf[i+1] == 0 {
					break
				}
			}
		}
		i++
	}
	return kvs
}

func sendPqAuthenticationOk(conn net.Conn) error {
	var buf [9]byte
	buf[0] = 'R'
	binary.BigEndian.PutUint32(buf[1:], 8)
	binary.BigEndian.PutUint32(buf[5:], 0) // 0表示认证成功
	_, err := sendData(conn, buf[0:9])
	return err
}

func sendPqParameterStatus(conn net.Conn, key string, value string) error {
	var buf = make([]byte, 5, 128)
	buf[0] = 'S'
	binary.BigEndian.PutUint32(buf[1:], 0)
	buf = append(buf, []byte(key)...)
	buf = append(buf, 0)
	buf = append(buf, []byte(value)...)
	buf = append(buf, 0)
	binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1))
	_, err := sendData(conn, buf)
	return err
}

func sendPqBackendKeyData(conn net.Conn, pid uint32, key uint32) error {
	var buf [13]byte
	buf[0] = 'K'
	binary.BigEndian.PutUint32(buf[1:], 12)
	binary.BigEndian.PutUint32(buf[5:], pid)
	binary.BigEndian.PutUint32(buf[9:], key) // 0表示认证成功
	_, err := sendData(conn, buf[:13])
	return err
}

func sendPqReadyForQuery(conn net.Conn, transState byte) error {
	var buf [6]byte
	buf[0] = 'Z'
	binary.BigEndian.PutUint32(buf[1:], 5)
	buf[5] = transState
	_, err := sendData(conn, buf[:6])
	return err
}

func sendPqErrorResponse(conn net.Conn, errFields []string) error {
	var buf = make([]byte, 5, 128)
	buf[0] = 'E'
	binary.BigEndian.PutUint32(buf[1:], 0)
	for _, ef := range errFields {
		buf = append(buf, []byte(ef)...)
		buf = append(buf, 0)
	}
	buf = append(buf, 0)
	binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1))
	_, err := sendData(conn, buf)
	return err
}

/*
func sendPqParseCompletion(conn net.Conn) error {
	var recvBuf [5]byte
	recvBuf[0] = '1'
	binary.BigEndian.PutUint32(recvBuf[1:], 4)
	_, err := sendData(conn, recvBuf[:5])
	return err
}*/

func sendPqCloseCompletion(conn net.Conn) error {
	var buf [5]byte
	buf[0] = '3'
	binary.BigEndian.PutUint32(buf[1:], 4)
	_, err := sendData(conn, buf[:5])
	return err
}

func sendPqClosePrepare(conn net.Conn, prepareId int32) error {
	var buf = make([]byte, 0, 12)
	buf = append(buf, 'C', 0, 0, 0, 0, 'S')
	buf = append(buf, []byte(fmt.Sprintf("S%d", prepareId))...)
	buf = append(buf, 0)
	binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1))
	_, err := sendData(conn, buf)
	return err
}

func sendPqSync(conn net.Conn) error {
	var buf [5]byte
	buf[0] = 'S'
	binary.BigEndian.PutUint32(buf[1:], 4)
	_, err := sendData(conn, buf[:])
	return err
}

func sendRollback(conn net.Conn) error {
	var buf [15]byte
	buf[0] = 'Q'
	binary.BigEndian.PutUint32(buf[1:], 14)
	copy(buf[5:], "rollback;")
	buf[14] = 0
	_, err := sendData(conn, buf[:])
	return err
}

/*
清理事务
*/
func CleanupTrans(conn net.Conn) error {
	var err error
	err = sendRollback(conn)
	if err != nil {
		return err
	}

	var buf [1024]byte
	for {
		_, _, err = recvMessage(conn, buf[:])
		if err != nil {
			return err
		}
		if buf[0] == 'Z' { /*ReadyForQuery*/
			return nil
		}
	}
	return nil
}

func handleAuth(cliConn net.Conn, Pid uint32) (int, []*PgBackendConn) {
	var buf []byte
	var rbuf []byte
	var dataLen int32
	var pos int32 = 0
	//var n int32
	var err error
	var ver1 uint16
	var ver2 uint16

	var pool []*PgBackendConn

	buf = make([]byte, 4096)
	rbuf = make([]byte, 4096)

	dataLen, err = recvStartupPacket(cliConn, buf[:])
	if err != nil {
		log.Printf("Recv first startup packet from client error: %s\n", err.Error())
		cliConn.Close()
		return -1, nil
	}
	pos += dataLen

	//log.Printf("Recv from client %d bytes: %v", dataLen, recvBuf[0:dataLen])

	ver1 = binary.BigEndian.Uint16(buf[4:6])
	ver2 = binary.BigEndian.Uint16(buf[6:8])
	if ver1 == 1234 && ver2 == 5679 { /* 这是客户端发过来测试是否可以进行SSL通信*/
		rbuf[0] = 'N'
		_, err = cliConn.Write(rbuf[0:1])
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			//srv_conn.Close()
			cliConn.Close()
			return -1, nil
		}
		/* 重新收数据包*/
		dataLen, err = recvStartupPacket(cliConn, buf[:])
		if err != nil {
			log.Printf("Recv second startup packet from client error: %s\n", err.Error())
			cliConn.Close()
			return -1, nil
		}
		pos = dataLen
		ver1 = binary.BigEndian.Uint16(buf[4:6])
		ver2 = binary.BigEndian.Uint16(buf[6:8])
	}

	//log.Printf("Protocol version is %d.%d\n", ver1, ver2)

	reqOpts := parseMulKeyValuePacket(buf[8:], dataLen-4)
	var user string
	var database string
	var ok bool

	user, ok = reqOpts["user"]
	if !ok {
		log.Printf("No 'user' in startup packet!")
		return -1, nil
	}
	database, ok = reqOpts["database"]
	if !ok {
		log.Printf("No 'database' in startup packet!")
		return -1, nil
	}

	var poolName string
	poolName = user + "." + database
	pool, ok = g_backend_pool[poolName]
	if !ok {
		log.Printf("User(%s), database(%s) not in pool!", user, database)
		return -1, nil
	}

	/*
		for k, v := range reqOpts {
			log.Printf("%s=%s\n", k, v)
		}*/

	var randomSalt [4]byte
	_, err = rand.Read(randomSalt[0:])
	if err != nil {
		log.Printf("Can not generate random salt: %s\n", err.Error())
		return -1, nil
	}

	//log.Printf("Generate random salt is %v\n", randomSalt)

	rbuf[0] = 'R'
	binary.BigEndian.PutUint32(rbuf[1:], 12)
	binary.BigEndian.PutUint32(rbuf[5:], 5)
	copy(rbuf[9:], randomSalt[0:4])
	//log.Printf("My reply should be %v\n", rbuf[0:13])
	_, err = cliConn.Write(rbuf[0:13])
	if err != nil {
		log.Printf("Reply to client error: %s\n", err.Error())
		cliConn.Close()
		return -1, nil
	}

	/* 从客户端接收 加密后的md5值 */
	_, _, err = recvMessage(cliConn, buf[:])
	if err != nil {
		log.Printf("Reply from client error: %s\n", err.Error())
		cliConn.Close()
		return -1, nil
	}

	if buf[0] != 'p' {
		log.Printf("Expect from client recv password message, but recv %c message\n", buf[0])
		cliConn.Close()
		return -1, nil
	}
	//log.Printf("Recv from client password message: %s", string(recvBuf[5:n]))
	md5AuthCalc(rbuf[:], user, pool[0].dbConf.Passwd, randomSalt[:])
	if bytes.Compare(rbuf[:35], buf[5:40]) == 0 {
		/* 回一个AuthenticationOk消息*/
		err = sendPqAuthenticationOk(cliConn)
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			cliConn.Close()
			return -1, nil
		}

		parms := map[string]string{
			"client_encoding":   "UTF8",
			"DateStyle":         "ISO, MDY",
			"integer_datetimes": "on",
			"IntervalStyle":     "postgres",
			"server_encoding":   "UTF8",
			"server_version":    "10.5",
			"TimeZone":          "PRC",
		}

		for key, value := range parms {
			err = sendPqParameterStatus(cliConn, key, value)
			if err != nil {
				log.Printf("Reply to client error: %s\n", err.Error())
				cliConn.Close()
				return -1, nil
			}
		}

		err = sendPqBackendKeyData(cliConn, Pid, 232323)
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			cliConn.Close()
			return -1, nil
		}

		err = sendPqReadyForQuery(cliConn, 'I')
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			cliConn.Close()
			return -1, nil
		}
		return 0, pool
	}

	var errFields = [...]string{
		"SFATAL",
		"VFATAL",
		"C28P01",
		"Mpassword authentication failed",
		"Fcstech.go",
		"L458",
		"Rauth_failed",
	}

	err = sendPqErrorResponse(cliConn, errFields[:])
	if err != nil {
		log.Printf("Reply to client error: %s\n", err.Error())
		cliConn.Close()
		return -1, nil
	}
	return 1, nil
}

/*
清除已记录为需要关闭的prepare
*/
func (p *PgBackendConn) CleanupNeedClosePrepare() {
	var err error
	p.Lock.Lock()
	defer p.Lock.Unlock()
	var prepareId int32
	for _, prepareId = range p.needClosePrepare {
		err = sendPqClosePrepare(p.Conn, prepareId)
		if err != nil {
			break
		}
		err = sendPqSync(p.Conn)
		if err != nil {
			break
		}

		var buf [1024]byte
		for {
			_, _, err = recvMessage(p.Conn, buf[:])
			if err != nil {
				log.Printf("Recv from DbConfig error: %s\n", err.Error())
				return
			}
			if buf[0] == 'Z' { /*ReadyForQuery*/
				break
			}
			if buf[0] == 'E' {
				log.Printf("Cleanup prepare failed!")
			}
		}
	}
	p.needClosePrepare = nil
}

func getBackend(pool []*PgBackendConn) *PgBackendConn {
	var cnt = 10
	for {
		for _, backend := range pool {
			if atomic.CompareAndSwapInt32(&backend.State, 0, 1) {
				//backend.CleanupNeedClosePrepare()
				return backend
			}
		}
		/* 如果没有找到，则等5ms*/
		time.Sleep(time.Duration(cnt+1) * 5 * time.Millisecond)
		//time.Sleep(time.Millisecond)
		cnt += 1
		if cnt%10 == 0 {
			log.Printf("Wait 10 times for get backend connection!")
		}

		if cnt > 200 {
			cnt = 200
		}
	}
	return nil
}

type CuPre struct {
	backendPrepareId   int32
	prepareRequestData []byte
	prepareRequestLen  int32
}

type ConnContext struct {
	msgList  [][]byte
	msgCount int32
	recvBuf  []byte
	sendBuf  []byte
	sendLen  int32
	//recvLen  int32
	//leftLen  int32

	cachedPrepare CachedPrepare
	transState    byte /* session的事务状态*/
	pool          []*PgBackendConn

	isInUnnamedPrepared bool
	unnamePrepareData   []byte

	/*客户端发起的请求中，会有多个P消息和一个S消息，所以需要把多个P消息暂存在cupreMap(Cumulative Prepare)中*/
	cupreMap map[string]*CuPre

	//prepareRequestData []byte
	//prepareRequestLen int32
	//prepareName string
	//backendPrepareId int32

	Pid uint32

	cliConn net.Conn

	isGetBackend  bool
	pBackConn     *PgBackendConn
	pSendBackConn *PgBackendConn
}

func (ctx *ConnContext) Init(cliConn net.Conn) {
	ctx.cliConn = cliConn
	ctx.recvBuf = make([]byte, BUF_SIZE)
	ctx.sendBuf = make([]byte, BUF_SIZE+1024)
	ctx.Pid = atomic.AddUint32(&g_next_pid, 1)

	ctx.msgList = make([][]byte, 512)

	ctx.isGetBackend = false
	ctx.pBackConn = nil
	ctx.isInUnnamedPrepared = false
	ctx.transState = 'I'

	//ctx.prepareRequestLen = 0

	ctx.cupreMap = make(map[string]*CuPre)
}

func (ctx *ConnContext) recvRequest() error {
	var pos int32
	var err error
	var n int
	var pktpos int
	var pktlen int

	ctx.msgCount = 0
	pos = 0
	pktpos = 0

	for {
		//TCHDEBUG log.Printf("Client(%d): RC: begin...", ctx.Pid)
		n, err = ctx.cliConn.Read(ctx.recvBuf[pos:BUF_SIZE])
		if err != nil {
			if err != nil {
				return err
			}
		}
		pos += int32(n)
		if pos < int32(pktpos)+5 {
			continue
		}
		pktlen = int(binary.BigEndian.Uint32(ctx.recvBuf[pktpos+1 : pktpos+5]))
		if pos < int32(pktpos+pktlen)+1 {
			continue
		}

		if pos > BUF_SIZE-64 {
			log.Panicf("Client(%d): request too long!\n", ctx.Pid)
		}

		for pktpos+pktlen+1 <= int(pos) {
			ctx.msgList[ctx.msgCount] = ctx.recvBuf[pktpos : pktpos+pktlen+1]
			//TCHDEBUG log.Printf("Client(%d): RC: message=%c%d%v", ctx.Pid, ctx.msgList[ctx.msgCount][0], pktlen+1, ctx.msgList[ctx.msgCount])
			ctx.msgCount++
			if ctx.msgList[ctx.msgCount-1][0] == 'S' {
				return nil
			}
			pktpos += pktlen + 1
			pktlen = int(binary.BigEndian.Uint32(ctx.recvBuf[pktpos+1 : pktpos+5]))
		}
		return nil
	}

	return nil
}

func (ctx *ConnContext) ProcessX() { /* Terminate消息*/
	/* 做一些清理工作，把此后端连接上的事务回滚掉*/
	if ctx.transState != 'I' {
		CleanupTrans(ctx.pBackConn.Conn)
	}
	if ctx.isGetBackend {
		atomic.StoreInt32(&ctx.pBackConn.State, 0)
	}
	ctx.cliConn.Close()
	log.Printf("Client(%d): Close Connect\n", ctx.Pid)
}

//func (ctx *ConnContext) transLeftDataToBackend() error {
//    var err error
//    var isSrc bool
//	log.Printf("Client(%d): SB: data=%v\n", ctx.Pid, ctx.rewritebuf[:])
//	err, isSrc = transData(ctx.cliConn, ctx.pBackConn.Conn, ctx.leftLen, ctx.recvBuf[:])
//	if err != nil {
//		if isSrc { /* 是客户端连接中断*/
//			log.Printf("Client(%d): SB(%d): forward failed: client error\n", ctx.Pid, ctx.pBackConn.Id)
//			/* 做一些清理工作，把此后端连接上的事务回滚掉*/
//			/* FIXME: 有可能需要把后端连接也停掉*/
//			if ctx.transState != 'I' {
//				CleanupTrans(ctx.pBackConn.Conn)
//			}
//			atomic.StoreInt32(&ctx.pBackConn.State, 0)
//			return err
//		} else { /* 后端连接中断 */
//			log.Printf("Client(%d, Q): SB(%d): forward failed: backend error\n", ctx.Pid, ctx.pBackConn.Id)
//			ctx.cliConn.Close()
//			ctx.pBackConn.Reconnect()
//			atomic.StoreInt32(&ctx.pBackConn.State, 0)
//			return err
//		}
//	}
//	return nil
//}

func (ctx *ConnContext) ProcessQ() error { /* 这是 Query 简单查询 */
	var err error

	ctx.isInUnnamedPrepared = false

	if !ctx.isGetBackend {
		//log.Printf("Get connect from pool.\n")
		ctx.pBackConn = getBackend(ctx.pool)
		ctx.isGetBackend = true
		//TCHDEBUG log.Printf("Client(%d, Q): hold backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		//reConnCnt = ctx.pBackConn.ReConnCnt
	}
	/* 直接转发 */
	for {
		_, err = sendData(ctx.pBackConn.Conn, ctx.msgList[0])
		if err != nil {
			log.Printf("Client(%d, Q): SB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, err.Error())
			if ctx.transState != 'I' { /* 如果是在事务中，则无法恢复 */
				ctx.cliConn.Close()
				ctx.pBackConn.Reconnect()
				return err
			}
			ctx.pBackConn.Reconnect()
			return nil
		}

		//if ctx.leftLen > 0 { /* 包的数据还没有收完， 把后续的数据直接转发到后端 */
		//	log.Printf("Client(%d, Q): FB(%d): datalen=%d\n", ctx.Pid, ctx.pBackConn.Id, ctx.leftLen)
		//	err = ctx.transLeftDataToBackend()
		//	if err != nil {
		//		return err
		//	}
		//}

		break
	}
	ctx.pSendBackConn = ctx.pBackConn
	clientErr, backendErr := ctx.forwardToClient()
	if clientErr != nil {
		return clientErr
	} else {
		return backendErr
	}
}

/*
 返回clientErr, backendErr
*/
func (ctx *ConnContext) forwardToClient() (error, error) {
	var isSuccess bool
	var n int
	var clientErr error = nil
	var backendErr error = nil
	var pos int
	var pktpos int
	var pktlen int
	var msgType byte

	//var partialHappened bool = false

	//TCHDEBUG log.Printf("*****RETURN Backend(%d) => Client(%d)\n", ctx.pBackConn.Id, ctx.Pid)

	if ctx.pSendBackConn.Id != ctx.pBackConn.Id {
		log.Panicf("recv backend not the send backend!!!")
	}

	isSuccess = true
	pos = 0    //记录缓冲区记录数据的点
	pktpos = 0 //记录消息的开始位置
	for {
		//partialHappened = false
		//TCHDEBUG log.Printf("Client(%d): RB(%d): begin ...\n", ctx.Pid, ctx.pBackConn.Id)
		n, backendErr = ctx.pBackConn.Conn.Read(ctx.recvBuf[pos : BUF_SIZE-MAX_ERROR_MSG_SIZE])
		if backendErr != nil {
			log.Printf("Client(%d): RB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, backendErr.Error())
			ctx.cliConn.Close()
			ctx.pBackConn.Reconnect()
			return clientErr, backendErr
		}
		pos += n
		for pktpos < pos {
			msgType = ctx.recvBuf[pktpos]
			/*保证包中的4字节长度字节都被接收下来了(如果没有收下来，会再次收下来*/
			if pktpos > pos-5 {
				//partialHappened = true
				//TCHDEBUG log.Printf("Client(%d): RB(%d): begin ...\n", ctx.Pid, ctx.pBackConn.Id)
				n, backendErr = ctx.pBackConn.Conn.Read(ctx.recvBuf[pos:BUF_SIZE])
				if backendErr != nil {
					log.Printf("Client(%d): RB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, backendErr.Error())
					ctx.cliConn.Close()
					ctx.pBackConn.Reconnect()
					return clientErr, backendErr
				}
				pos += n
				continue
			}

			pktlen = int(binary.BigEndian.Uint32(ctx.recvBuf[pktpos+1 : pktpos+5]))
			if pktlen > int(BUF_SIZE) || pktlen < 4 {
				log.Printf("message is too long(more then %d)\n", BUF_SIZE)
			}
			//log.Printf("Client(%d): RB(%d): %c%d\n", ctx.Pid, ctx.pBackConn.Id, msgType, pktlen)

			/* 保证Z、E包都接收下来了*/
			if (msgType == 'Z' || msgType == 'E') && pktpos+pktlen+1 > pos {
				if pktlen > int(MAX_ERROR_MSG_SIZE)-1 {
					log.Panicf("E message too long(%d more then %d)!!!", pktlen, MAX_ERROR_MSG_SIZE-1)
				}

				//TCHDEBUG log.Printf("Client(%d): RB(%d): begin ...\n", ctx.Pid, ctx.pBackConn.Id)
				n, backendErr = ctx.pBackConn.Conn.Read(ctx.recvBuf[pos:BUF_SIZE])
				if backendErr != nil {
					log.Printf("Client(%d): RB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, backendErr.Error())
					ctx.cliConn.Close()
					ctx.pBackConn.Reconnect()
					return clientErr, backendErr
				}
				pos += n
				continue

			}

			if msgType == 'Z' {
				ctx.transState = ctx.recvBuf[pktpos+5]
			}
			if msgType == 'E' {
				isSuccess = false
				printBackendErrorMessage(ctx.recvBuf[pktpos:])
			}

			pktpos += pktlen + 1
		}

		//if pktpos > pos {
		//	log.Printf("pktpos(%d) > pos(%d)\n", pktpos, pos)
		//}

		//if partialHappened {
		//	log.Printf("partial happened!!!\n")
		//}

		if clientErr == nil {
			//TCHDEBUG log.Printf("Client(%d): SC: data=%c%d%v\n", ctx.Pid, ctx.recvBuf[0], n, ctx.recvBuf[:n])
			_, clientErr = sendData(ctx.cliConn, ctx.recvBuf[0:pos])
			if clientErr != nil {
				log.Printf("Client(%d): SC: ERROR: %s\n", ctx.Pid, clientErr.Error())
				ctx.cliConn.Close()
			}
		}

		if msgType == 'Z' && pktpos == pos {
			break
		}

		pktpos -= pos
		pos = 0
	}

	if clientErr != nil {
		isSuccess = false
	}
	if isSuccess {
		if !ctx.isInUnnamedPrepared {
			for prepareName, cuPre := range ctx.cupreMap {
				var pdata *PrepareData
				if cuPre.prepareRequestLen == 0 { /* 这是prepare的数据已缓存，而之前这个backend没有parse的情况*/
					var ok bool
					pdata, ok = ctx.cachedPrepare.Get(prepareName)
					if !ok {
						log.Panicf("BUG!!!!!!\n")
					}
				} else {
					pdata = new(PrepareData)
					ctx.cachedPrepare.AddPrepare(prepareName, pdata)
					pdata.PrepareRequest = cuPre.prepareRequestData
				}

				pdata.BackendMap = make(map[int32]*PrepareInBackend)
				pib := new(PrepareInBackend)
				pib.PrepareId = cuPre.backendPrepareId
				pib.BackConn = ctx.pBackConn
				pib.ReConnCnt = ctx.pBackConn.ReConnCnt /* 把后端连接的当前重连次数记录下来，如果在以后，后端重连后，两者就不一样了，就知道后端被重连了*/
				pdata.BackendMap[ctx.pBackConn.Id] = pib
				log.Printf("Client(%d): store prepare name=%s to backend(%d), backendPrepareId=%d\n",
					ctx.Pid, prepareName, ctx.pBackConn.Id, cuPre.backendPrepareId)
			}
			if len(ctx.cupreMap) > 1 {
				log.Printf("many prepare in one request!")
			}
		}
	}

	/*把临时放prepare data的map清空*/
	ctx.cupreMap = make(map[string]*CuPre)

	if (clientErr != nil) || (backendErr != nil) { /*出现一些问题*/
		/* 做一些清理工作，把此后端连接上的事务回滚掉*/
		if ctx.transState != 'I' {
			log.Printf("Client(%d, S): Client is closed, cleanup backend(%d) transacation\n",
				ctx.Pid, ctx.pBackConn.Id)
			CleanupTrans(ctx.pBackConn.Conn)
		}
		if ctx.isGetBackend {
			log.Printf("Client(%d, S): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return clientErr, backendErr
	}

	if !isSuccess {
		//log.Panicf("Client(%d, S): ERROR debug!!!\n", ctx.Pid)
	}

	/*这是没有发生错误的情况*/
	if ctx.transState == 'I' { /*释放后端连接*/
		//TCHDEBUG log.Printf("Client(%d, S): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		atomic.StoreInt32(&ctx.pBackConn.State, 0)
		ctx.isGetBackend = false
		ctx.pBackConn = nil
	}
	return nil, nil
}

/*
 返回clientErr, backendErr
*/
func (ctx *ConnContext) forwardToClient2() (error, error) {
	var isSuccess bool
	var n int32
	var clientErr error = nil
	var backendErr error = nil

	//TCHDEBUG log.Printf("*****RETURN Backend(%d) => Client(%d)\n", ctx.pBackConn.Id, ctx.Pid)

	if ctx.pSendBackConn.Id != ctx.pBackConn.Id {
		log.Panicf("recv backend not the send backend!!!")
	}

	isSuccess = true
	for {
		//TCHDEBUG log.Printf("Client(%d): RB(%d): begin ...\n", ctx.Pid, ctx.pBackConn.Id)
		n, _, backendErr = recvMessage(ctx.pBackConn.Conn, ctx.recvBuf[:])
		if backendErr != nil {
			log.Printf("Client(%d): RB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, backendErr.Error())
			ctx.cliConn.Close()
			ctx.pBackConn.Reconnect()
			return clientErr, backendErr
		}
		//TCHDEBUG log.Printf("Client(%d): RB(%d): data=%c%d%v\n", ctx.Pid, ctx.pBackConn.Id, ctx.recvBuf[0], n, ctx.recvBuf[:n])
		//log.Printf("#### Client(%d): RB(%c)\n", ctx.Pid, ctx.recvBuf[0])
		if ctx.recvBuf[0] == 'Z' { /*ReadyForQuery*/
			ctx.transState = ctx.recvBuf[5]
		}

		if ctx.recvBuf[0] == 'E' {
			isSuccess = false
			printBackendErrorMessage(ctx.recvBuf[:])
		}

		if clientErr == nil {
			//TCHDEBUG log.Printf("Client(%d): SC: data=%c%d%v\n", ctx.Pid, ctx.recvBuf[0], n, ctx.recvBuf[:n])
			n, clientErr = sendData(ctx.cliConn, ctx.recvBuf[0:n])
			if clientErr != nil {
				log.Printf("Client(%d): SC: ERROR: %s\n", ctx.Pid, clientErr.Error())
				ctx.cliConn.Close()
			}
		}

		if ctx.recvBuf[0] == 'Z' { /* Ready for Query */
			break
		}
	}
	if clientErr != nil {
		isSuccess = false
	}
	if isSuccess {
		if !ctx.isInUnnamedPrepared {
			for prepareName, cuPre := range ctx.cupreMap {
				var pdata *PrepareData
				if cuPre.prepareRequestLen == 0 { /* 这是prepare的数据已缓存，而之前这个backend没有parse的情况*/
					var ok bool
					pdata, ok = ctx.cachedPrepare.Get(prepareName)
					if !ok {
						log.Panicf("BUG!!!!!!\n")
					}
				} else {
					pdata = new(PrepareData)
					ctx.cachedPrepare.AddPrepare(prepareName, pdata)
					pdata.PrepareRequest = cuPre.prepareRequestData
				}

				pdata.BackendMap = make(map[int32]*PrepareInBackend)
				pib := new(PrepareInBackend)
				pib.PrepareId = cuPre.backendPrepareId
				pib.BackConn = ctx.pBackConn
				pib.ReConnCnt = ctx.pBackConn.ReConnCnt /* 把后端连接的当前重连次数记录下来，如果在以后，后端重连后，两者就不一样了，就知道后端被重连了*/
				pdata.BackendMap[ctx.pBackConn.Id] = pib
				log.Printf("Client(%d): store prepare name=%s to backend(%d), pid=%d\n",
					ctx.Pid, prepareName, ctx.pBackConn.Id, cuPre.backendPrepareId)
			}
			if len(ctx.cupreMap) > 1 {
				log.Printf("many prepare in one request!")
			}
		}
	}

	/*把临时放prepare data的map清空*/
	ctx.cupreMap = make(map[string]*CuPre)

	if (clientErr != nil) || (backendErr != nil) { /*出现一些问题*/
		/* 做一些清理工作，把此后端连接上的事务回滚掉*/
		if ctx.transState != 'I' {
			log.Printf("Client(%d, S): Client is closed, cleanup backend(%d) transacation\n",
				ctx.Pid, ctx.pBackConn.Id)
			CleanupTrans(ctx.pBackConn.Conn)
		}
		if ctx.isGetBackend {
			log.Printf("Client(%d, S): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return clientErr, backendErr
	}

	if !isSuccess {
		//log.Panicf("Client(%d, S): ERROR debug!!!\n", ctx.Pid)
	}

	/*这是没有发生错误的情况*/
	if ctx.transState == 'I' { /*释放后端连接*/
		//TCHDEBUG log.Printf("Client(%d, S): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		atomic.StoreInt32(&ctx.pBackConn.State, 0)
		ctx.isGetBackend = false
		ctx.pBackConn = nil
	}
	return nil, nil
}

func ExtractSQL(buf []byte) string {
	var pos int32
	var begin int32
	//var prepareName string
	if buf[0] != 'P' {
		return ""
	}
	pos = 5
	for pos = 5; buf[pos] != 0; pos++ {
	}
	//prepareName = string(buf[5:pos])
	pos++
	begin = pos
	for pos = begin; buf[pos] != 0; pos++ {
	}
	return string(buf[begin:pos])
}

func ExtractPrepareName(buf []byte) string {
	var pos int32
	var begin int32
	var prepareName string
	if buf[0] == 'P' {
		pos = 5
		for pos = 5; buf[pos] != 0; pos++ {
		}
		prepareName = string(buf[5:pos])
		pos++
		begin = pos
		for pos = begin; buf[pos] != 0; pos++ {
		}
		//log.Printf("SQL=%s\n", string(buf[begin:pos]))
	} else if buf[0] == 'B' {
		/*第一个字段是portalName，通常portalName为空*/
		pos = 5
		for pos = 5; buf[pos] != 0; pos++ {
		}
		if buf[pos] != 0 {
			log.Panicf("BUG******: portal not empty!!!\n")
		}
		pos++
		/*这后面是prepare的名称*/
		begin = pos
		for ; buf[pos] != 0; pos++ {
		}
		prepareName = string(buf[begin:pos])
	} else if buf[0] == 'D' {
		pos = 6
		for pos = 6; buf[pos] != 0; pos++ {
		}
		prepareName = string(buf[6:pos])
	}
	return prepareName
}

func printBackendErrorMessage(buf []byte) {
	var pos int32
	var begin int32
	var dataLen int32
	dataLen = int32(binary.BigEndian.Uint32(buf[1:5]))
	begin = 5
	pos = begin
	for pos < dataLen+1 {
		for ; pos < dataLen+1 && buf[pos] != 0; pos++ {
		}
		if pos-begin < 2 {
			return
		}
		//TCHDEBUG log.Printf("%c(%s)\n", buf[begin], string(buf[begin+1:pos]))
		pos++
		begin = pos
	}
}

func (ctx *ConnContext) sendToBackend() error {
	var err error
	ctx.pSendBackConn = ctx.pBackConn
	//TCHDEBUG log.Printf("Client(%d): SB(%d): data=%c%d%v\n",
	//TCHDEBUG 	ctx.Pid, ctx.pBackConn.Id, ctx.sendBuf[0], len(ctx.sendBuf[:ctx.sendLen]), ctx.sendBuf[:ctx.sendLen])
	_, err = sendData(ctx.pBackConn.Conn, ctx.sendBuf[:ctx.sendLen])
	if err != nil {
		log.Printf("Client(%d): SB(%d, %c): ERROR : %s\n", ctx.Pid, ctx.pBackConn.Id, ctx.sendBuf[0], err.Error())
		ctx.cliConn.Close()
		log.Printf("Client(%d): reconnect backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		ctx.pBackConn.Reconnect()
		if ctx.isGetBackend {
			log.Printf("Client(%d): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return err
	}
	return nil
}

func (ctx *ConnContext) sendToBackendWithRetry() error {
	var err error
	ctx.pSendBackConn = ctx.pBackConn
	/* 把消息发到后端 */
	for {

		//TCHDEBUG log.Printf("Client(%d): SB(%d): data=%c%d%v\n",
		//TCHDEBUG 	ctx.Pid, ctx.pBackConn.Id, ctx.sendBuf[0], ctx.sendLen, ctx.sendBuf[:ctx.sendLen])
		_, err = sendData(ctx.pBackConn.Conn, ctx.sendBuf[:ctx.sendLen])
		if err == nil {
			break
		}
		log.Printf("Client(%d): SB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, err.Error())
		if ctx.transState != 'I' { /* 如果是在事务中，则无法恢复 */
			log.Printf("Client(%d): SB(%d): reconnect backend, close client\n", ctx.Pid, ctx.pBackConn.Id)
			ctx.cliConn.Close()
			ctx.pBackConn.Reconnect()
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			return err
		}
		ctx.pBackConn.Reconnect()
		//FIXME: 如果发到后端一直不成功，则变成死循环了。
	}
	return nil
}

func (ctx *ConnContext) handleError() {
	ctx.cliConn.Close()
	if ctx.transState != 'I' {
		CleanupTrans(ctx.pBackConn.Conn)
	}
	if ctx.isGetBackend {
		atomic.StoreInt32(&ctx.pBackConn.State, 0)
		ctx.isGetBackend = false
	}
}

//func (ctx *ConnContext) CumulatePrepare(msg []byte) {
//
//}

func (ctx *ConnContext) CumulatePrepare() {
	var i int32
	var prepareName string
	var cutPos int32
	var cutLen int32
	var tmpPrepareLen int32
	var tmpPrepareData []byte
	var tmpBackendPrepareId int32
	//var backendPrepareName string

	for i = 0; i < ctx.msgCount; i++ {
		if ctx.msgList[i][0] == 'P' {
			prepareName = ExtractPrepareName(ctx.msgList[i])

			if prepareName == "" { /*处理unnamed prepared statement的情况*/
				ctx.isInUnnamedPrepared = true
				tmpPrepareLen = int32(len(ctx.msgList[i]))
				ctx.unnamePrepareData = make([]byte, tmpPrepareLen)
				copy(ctx.unnamePrepareData, ctx.msgList[i])
				continue
			} else {
				ctx.isInUnnamedPrepared = false
				ctx.unnamePrepareData = nil
			}

			cutPos = int32(5 + len([]byte(prepareName)) + 1)
			cutLen = int32(len(ctx.msgList[i])) - cutPos

			// 5字节的消息头，12字节的prepareName
			tmpPrepareLen = cutLen + 5 + 12
			tmpPrepareData = make([]byte, tmpPrepareLen)
			copy(tmpPrepareData[17:], ctx.msgList[i][cutPos:])
			//copy(tmpPrepareData[tmpPrepareLen-5:], []byte{'S', 0, 0, 0, 4})

			tmpBackendPrepareId = ctx.pBackConn.AllocPrepareId()
			//backendPrepareName = fmt.Sprintf("S%d", tmpBackendPrepareId)

			cuPre := new(CuPre)
			cuPre.prepareRequestLen = tmpPrepareLen
			cuPre.prepareRequestData = tmpPrepareData
			cuPre.backendPrepareId = tmpBackendPrepareId
			ctx.cupreMap[prepareName] = cuPre

		}
	}

}

func rewritePrepareReq(backendPrepareName string, srcBuf []byte, dstBuf []byte) int32 {
	var pos int32
	var packetLen int32
	var oldPrepareNameLen int32
	var backendPrepareNameLen int32
	//var prepareName string
	var cutPos int32

	/*第一个字段是prepareName*/
	pos = 5
	for pos = 5; srcBuf[pos] != 0; pos++ {
	}
	oldPrepareNameLen = pos - 5
	//prepareName = string(srcBuf[5:pos])
	pos++
	cutPos = pos

	//生产新的prepare数据包的包头
	backendPrepareNameLen = int32(len([]byte(backendPrepareName)))

	/*prepare request包的长度，旧S包的长度+ （新旧包的prepareName的长度差）*/
	packetLen = int32(binary.BigEndian.Uint32(srcBuf[1:5])) + backendPrepareNameLen - oldPrepareNameLen

	dstBuf[0] = srcBuf[0]
	binary.BigEndian.PutUint32(dstBuf[1:], uint32(packetLen))
	copy(dstBuf[5:], []byte(backendPrepareName))
	dstBuf[5+backendPrepareNameLen] = 0
	copy(dstBuf[5+backendPrepareNameLen+1:], srcBuf[cutPos:])
	return 1 + packetLen
}

/*
重写bind消息包
*/
func rewriteBindReq(backendPrepareName string, srcBuf []byte, dstBuf []byte) int32 { /*重写P消息*/
	var pos int32
	var portalName []byte
	var portalNameLen int32
	var begin int32
	//var prepareName string
	var oldPrepareNameLen int32
	var backendPrepareNameLen int32
	var packetLen int32
	var cutPos int32

	/*第一个字段是portalName，通常portalName为空*/
	pos = 5
	for pos = 5; srcBuf[pos] != 0; pos++ {
	}
	portalName = make([]byte, pos-5)
	copy(portalName, srcBuf[5:pos])
	portalNameLen = pos - 5
	pos++
	/*这后面是prepare的名称*/
	begin = pos
	for ; srcBuf[pos] != 0; pos++ {
	}
	//prepareName = string(srcBuf[begin:pos])
	oldPrepareNameLen = pos - begin
	pos++
	cutPos = pos

	backendPrepareNameLen = int32(len([]byte(backendPrepareName)))
	/*新包的长度 = 旧包的长度 +（新旧包的prepareName的长度差）*/
	packetLen = int32(binary.BigEndian.Uint32(srcBuf[1:5])) + backendPrepareNameLen - oldPrepareNameLen

	dstBuf[0] = srcBuf[0]
	binary.BigEndian.PutUint32(dstBuf[1:], uint32(packetLen))
	if portalNameLen > 0 {
		copy(dstBuf[5:], portalName)
	}
	pos = 5 + portalNameLen
	dstBuf[pos] = 0
	pos++
	copy(dstBuf[pos:], []byte(backendPrepareName))
	pos += backendPrepareNameLen
	dstBuf[pos] = 0
	pos++
	copy(dstBuf[pos:], srcBuf[cutPos:])

	return packetLen + 1
}

/*
重写Describe消息包
返回：prepareName
*/
func rewriteDescribeReq(backendPrepareName string, srcBuf []byte, dstBuf []byte) int32 { /*重写D消息*/
	var pos int32
	var packetLen int32
	var oldPrepareNameLen int32
	var backendPrepareNameLen int32
	var cutPos int32

	/*应该是'S', 然后就是prepare name*/
	pos = 6
	for pos = 6; srcBuf[pos] != 0; pos++ {
	}
	oldPrepareNameLen = pos - 6
	//prepareName = string(srcBuf[6:pos])
	pos++
	cutPos = pos

	backendPrepareNameLen = int32(len([]byte(backendPrepareName)))
	/*prepare request包的长度，旧S包的长度+ （新旧包的prepareName的长度差）*/
	packetLen = int32(binary.BigEndian.Uint32(srcBuf[1:5])) + backendPrepareNameLen - oldPrepareNameLen
	/* prepare request包的长度 = P消息中长度域+1，+1是因为消息的第一个字节标识消息类型*/

	dstBuf[0] = srcBuf[0]
	dstBuf[5] = srcBuf[5]
	binary.BigEndian.PutUint32(dstBuf[1:], uint32(packetLen))
	copy(dstBuf[6:], []byte(backendPrepareName))
	dstBuf[6+backendPrepareNameLen] = 0
	pos = 6 + backendPrepareNameLen + 1
	copy(dstBuf[pos:], srcBuf[cutPos:])

	return 1 + packetLen
}

func noused(n int32) int32 {
	return n
}

/*则重新发prepare数据到这个后端上*/
func (ctx *ConnContext) reSendPrepareData(needPrepareMap map[string]*PrepareIdData) error {
	var err error
	var newPrepareNameLen int32
	var backendPrepareName string
	var beginPos int32
	var packetLen int32
	var PrepareRequest []byte
	var n int32
	var isSuccess bool

	for prepareName, prepareIdData := range needPrepareMap {
		log.Printf("Client(%d): SB(%d): reprepare %s\n", ctx.Pid, ctx.pBackConn.Id, prepareName)
		if prepareName == "" { /*这是未命名的prepare*/
			beginPos = 0
			PrepareRequest = prepareIdData.PrepareRequest
		} else {
			backendPrepareName = fmt.Sprintf("S%d", prepareIdData.PrepareId)
			//backendPrepareName = fmt.Sprintf("S%d", pib.PrepareId)
			newPrepareNameLen = int32(len([]byte(backendPrepareName)))
			beginPos = 11 - newPrepareNameLen
			PrepareRequest = prepareIdData.PrepareRequest
			PrepareRequest[beginPos] = 'P'
			packetLen = int32(len(PrepareRequest)) - 17 + newPrepareNameLen + 1 + 4
			binary.BigEndian.PutUint32(PrepareRequest[beginPos+1:], uint32(packetLen))
			copy(PrepareRequest[beginPos+5:], []byte(backendPrepareName))
			PrepareRequest[beginPos+5+newPrepareNameLen] = 0
		}

		//TCHDEBUG log.Printf("Client(%d): need send P(%s) to backend(%d), new prepare name=%s\n",
		//TCHDEBUG 	ctx.Pid, prepareName, ctx.pBackConn.Id, backendPrepareName)

		_, err = sendData(ctx.pBackConn.Conn, PrepareRequest[beginPos:])
		if err != nil {
			log.Printf("Client(%d): SB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, err.Error())
			ctx.cliConn.Close()
			log.Printf("Client(%d): reconnect backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			ctx.pBackConn.Reconnect()
			if ctx.isGetBackend {
				log.Printf("Client(%d): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}
	}
	/*最后再发一个sync消息*/
	_, err = sendData(ctx.pBackConn.Conn, []byte{'S', 0, 0, 0, 4})
	if err != nil {
		log.Printf("Client(%d): SB(%d): ERROR: %s\n", ctx.Pid, ctx.pBackConn.Id, err.Error())
		ctx.cliConn.Close()
		log.Printf("Client(%d): reconnect backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		ctx.pBackConn.Reconnect()
		if ctx.isGetBackend {
			log.Printf("Client(%d): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return err
	}

	isSuccess = true
	for {
		//TCHDEBUG log.Printf("Client(%d, B): RB(%d): begin recv...\n", ctx.Pid, ctx.pBackConn.Id)
		n, _, err = recvMessage(ctx.pBackConn.Conn, ctx.recvBuf[0:])
		if err != nil {
			log.Printf("Client(%d, B): RB(%d): ERROR: len=%d, %s\n", ctx.Pid, ctx.pBackConn.Id, n, err.Error())
			ctx.cliConn.Close()
			ctx.pBackConn.Reconnect()
			if ctx.isGetBackend {
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}

		if ctx.recvBuf[0] == 'E' {
			isSuccess = false
			printBackendErrorMessage(ctx.recvBuf[:])
		}

		//TCHDEBUG log.Printf("Client(%d, B): RB(%d, %c): data=%v\n", ctx.Pid, ctx.pBackConn.Id, ctx.recvBuf[0], ctx.recvBuf[:n])
		if ctx.recvBuf[0] == 'Z' {
			break
		}
	}

	if isSuccess {
		for prepareName, prepareIdData := range needPrepareMap {
			if prepareName == "" {
				continue
			}
			pdata, ok := ctx.cachedPrepare.Get(prepareName)
			if !ok {
				log.Panicf("BUG!!!!!!\n")
			}
			prepareInBackend := new(PrepareInBackend)
			prepareInBackend.PrepareId = prepareIdData.PrepareId
			prepareInBackend.BackConn = ctx.pBackConn
			prepareInBackend.ReConnCnt = ctx.pBackConn.ReConnCnt
			pdata.BackendMap[ctx.pBackConn.Id] = prepareInBackend
			log.Printf("Client(%d): store prepare name=%s to backend(%d), backendPrepareId=%d(reprepare)\n",
				ctx.Pid, prepareName, ctx.pBackConn.Id, prepareIdData.PrepareId)
		}
	}

	return nil
}

func (ctx *ConnContext) ProcessExtendedQuery() error { /* 处理Extended Query消息 */
	var err error
	var i int32
	var prepareName string
	var backendPrepareName string
	var pos int32
	var pdata *PrepareData
	var pib *PrepareInBackend

	var needPrepareMap map[string]*PrepareIdData
	var prepareId int32

	var haveUnnamedP bool  /*在请求中是否有未命名的prepare消息*/
	var haveUnnamedBD bool /*在请求中是否有未命名的BIND或Describe消息*/

	/* 现获得一个backend */
	if !ctx.isGetBackend {
		ctx.pBackConn = getBackend(ctx.pool)
		ctx.isGetBackend = true
		//TCHDEBUG log.Printf("Client(%d): hold backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
	}

	ctx.CumulatePrepare()
	needPrepareMap = make(map[string]*PrepareIdData)

	haveUnnamedP = false
	haveUnnamedBD = false

	/*把重写过的数据放到ctx.dstBuf中*/
	pos = 0
	for i = 0; i < ctx.msgCount; i++ {
		if ctx.msgList[i][0] == 'P' {
			//TCHDEBUG log.Printf("Client(%d), SQL=%s\n", ctx.Pid, ExtractSQL(ctx.msgList[i]))
		}

		if ctx.msgList[i][0] == 'P' || ctx.msgList[i][0] == 'B' || ctx.msgList[i][0] == 'D' {
			prepareName = ExtractPrepareName(ctx.msgList[i])
			if ctx.msgList[i][0] == 'P' && prepareName == "" {
				haveUnnamedP = true
			}

			if (ctx.msgList[i][0] == 'B' || ctx.msgList[i][0] == 'D') && prepareName == "" {
				haveUnnamedBD = true
			}

			notNeedRewrite := false
			if prepareName == "" { /*匿名的prepare*/
				notNeedRewrite = true
			}

			if ctx.msgList[i][0] == 'D' && ctx.msgList[i][5] == 'P' {
				notNeedRewrite = true
			}
			if notNeedRewrite {
				copy(ctx.sendBuf[pos:], ctx.msgList[i])
				pos += int32(len(ctx.msgList[i]))
				continue
			}

			if cuPre, ok := ctx.cupreMap[prepareName]; ok {
				prepareId = cuPre.backendPrepareId
			} else if prepareIdData, ok := needPrepareMap[prepareName]; ok { /*前面已经记录过*/
				prepareId = prepareIdData.PrepareId
			} else {
				pdata, ok = ctx.cachedPrepare.Get(prepareName)
				if !ok { /* 发现一个不存在的prepare */
					err = ctx.handlePrepareNameNotExists(prepareName)
					return err
				}

				pib, ok = pdata.BackendMap[ctx.pBackConn.Id]
				if !ok { /*未被parse过，需要parse*/
					prepareId = ctx.pBackConn.AllocPrepareId()
					prepareIdData := new(PrepareIdData)
					prepareIdData.PrepareId = prepareId
					prepareIdData.PrepareRequest = pdata.PrepareRequest
					needPrepareMap[prepareName] = prepareIdData
				} else {
					prepareId = pib.PrepareId
				}

			}
			backendPrepareName = fmt.Sprintf("S%d", prepareId)
			if ctx.msgList[i][0] == 'P' {
				pos += rewritePrepareReq(backendPrepareName, ctx.msgList[i], ctx.sendBuf[pos:])
			} else if ctx.msgList[i][0] == 'B' {
				pos += rewriteBindReq(backendPrepareName, ctx.msgList[i], ctx.sendBuf[pos:])
			} else if ctx.msgList[i][0] == 'D' {
				pos += rewriteDescribeReq(backendPrepareName, ctx.msgList[i], ctx.sendBuf[pos:])
			}

		} else {
			copy(ctx.sendBuf[pos:], ctx.msgList[i])
			pos += int32(len(ctx.msgList[i]))
		}
	}
	ctx.sendLen = pos

	if (!haveUnnamedP) && haveUnnamedBD { /* 当请求中没有未命名的P消息，而只有未命名的B或D消息，需要重新发未命名的P消息到后端*/
		if ctx.Pid != ctx.pBackConn.LastFrontId {
			prepareId = -1
			prepareIdData := new(PrepareIdData)
			prepareIdData.PrepareId = prepareId
			prepareIdData.PrepareRequest = ctx.unnamePrepareData
			needPrepareMap[""] = prepareIdData
		}
	}
	ctx.pBackConn.LastFrontId = ctx.Pid

	if len(needPrepareMap) > 0 {
		err = ctx.reSendPrepareData(needPrepareMap)
		if err != nil {
			return err
		}
	}

	err = ctx.sendToBackend()
	if err != nil {
		return err
	}
	var clientErr error = nil
	var backendErr error = nil
	err = nil
	clientErr, backendErr = ctx.forwardToClient()
	if clientErr != nil {
		err = clientErr
	} else if backendErr != nil {
		err = backendErr
	}
	return err
}

func (ctx *ConnContext) handlePrepareNameNotExists(prepareName string) error {
	var err error
	var n int32

	log.Panicf("Client(%d, B): ERROR: unknown prepare name=%s\n", ctx.Pid, prepareName)
	/* 先从客户端把后面的数据包接收完，然后再发送错误消息到前端 */
	for {
		//TCHDEBUG log.Printf("Client(%d, B): RC: begin ...\n", ctx.Pid)
		n, _, err = recvMessage(ctx.cliConn, ctx.recvBuf[:])
		if err != nil {
			noused(n)
			log.Printf("Client(%d, B): RC: ERROR : %s\n", ctx.Pid, err.Error())
			ctx.cliConn.Close()
			/* 做一些清理工作，把此后端连接上的事务回滚掉*/
			if ctx.transState != 'I' {
				log.Printf("Client(%d, B): Cleanup backend(%d) transaction\n", ctx.Pid, ctx.pBackConn.Id)
				CleanupTrans(ctx.pBackConn.Conn)
			}
			if ctx.isGetBackend {
				log.Printf("Client(%d, B): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}
		//TCHDEBUG log.Printf("Client(%d, B): RC(%c): len=%d, data=%v\n", ctx.Pid, ctx.recvBuf[0], n, ctx.recvBuf[:n])
		if ctx.recvBuf[0] == 'S' {
			break
		}
	}
	var errFields = [...]string{
		"SFATAL",
		"VFATAL",
		"C26000",
		"Mprepare not exists",
		"Fcstech.go",
		"L781",
		"RBind_error",
	}
	log.Printf("Client(%d, B): SC: Bind error\n", ctx.Pid)
	err = sendPqErrorResponse(ctx.cliConn, errFields[:])
	if err != nil {
		log.Printf("Client(%d, B): SC: ERROR: %s\n", ctx.Pid, err.Error())
		ctx.cliConn.Close()
		if ctx.transState != 'I' {
			log.Printf("Client(%d, B): Cleanup backend(%d) transaction\n", ctx.Pid, ctx.pBackConn.Id)
			CleanupTrans(ctx.pBackConn.Conn)
		}
		if ctx.isGetBackend {
			log.Printf("Client(%d, B): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return errors.New("bind error")
	}
	log.Printf("Client(%d, B): SC: ready for query\n", ctx.Pid)
	sendPqReadyForQuery(ctx.cliConn, ctx.transState)
	ctx.cliConn.Close()
	if ctx.transState != 'I' {
		log.Printf("Client(%d, B): Cleanup backend(%d) transaction\n", ctx.Pid, ctx.pBackConn.Id)
		CleanupTrans(ctx.pBackConn.Conn)
	}
	if ctx.isGetBackend {
		log.Printf("Client(%d, B): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
		atomic.StoreInt32(&ctx.pBackConn.State, 0)
		ctx.isGetBackend = false
	}
	return errors.New("unknown prepare name")

}

func (ctx *ConnContext) ProcessC() error { /* 处理close消息 */
	var err error
	if ctx.recvBuf[5] != 'S' { /* 另一个可行的值为'P'，指示关闭portal ，但libpq不支持直接操作portal */
		var errFields = [...]string{
			"SFATAL",
			"VFATAL",
			"C0A000",
			"MOnly support close prepare stmt.",
			"Fwww.cstech.ltd",
			"L1480",
			"Rfeature_not_supported",
		}
		log.Printf("Client(%d, C): SC: ERROR: L1480, feature_not_supported\n", ctx.Pid)
		err = sendPqErrorResponse(ctx.cliConn, errFields[:])
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			ctx.cliConn.Close()
			if ctx.transState != 'I' {
				CleanupTrans(ctx.pBackConn.Conn)
			}
			if ctx.isGetBackend {
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}
		log.Printf("Client(%d, C): SC: Ready for query\n", ctx.Pid)
		err = sendPqReadyForQuery(ctx.cliConn, ctx.transState)
		if err != nil {
			log.Printf("Reply to client error: %s\n", err.Error())
			ctx.cliConn.Close()
			if ctx.transState != 'I' {
				CleanupTrans(ctx.pBackConn.Conn)
			}
			if ctx.isGetBackend {
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}
	}

	prepareName := string(ctx.msgList[0][6:])
	_, ok := ctx.cachedPrepare.Get(prepareName)
	if !ok { /* 发送了一个不存在的prepare */
		var errFields = [...]string{
			"SFATAL",
			"VFATAL",
			"C26000",
			"Mprepare not exists",
			"Fwww.cstech.ltd",
			"L1524",
			"Rinvalid_sql_statement_name",
		}
		//log.Printf("Client(%d, C): SC: ERROR: L1524, invalid_sql_statement_name\n", ctx.Pid)
		log.Panicf("Client(%d, C): SC: ERROR: L1524, invalid_sql_statement_name\n", ctx.Pid)
		err = sendPqErrorResponse(ctx.cliConn, errFields[:])
		if err != nil {
			log.Printf("Client(%d, C): SC: ERROR: %s\n", ctx.Pid, err.Error())
			ctx.cliConn.Close()
			if ctx.transState != 'I' {
				CleanupTrans(ctx.pBackConn.Conn)
			}
			if ctx.isGetBackend {
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			return err
		}
		sendPqReadyForQuery(ctx.cliConn, ctx.transState)
	}
	ctx.cachedPrepare.DeletePrepare(prepareName)
	log.Printf("Client(%d, C): SC: close client\n", ctx.Pid)
	err = sendPqCloseCompletion(ctx.cliConn)
	if err != nil {
		log.Printf("Client(%d, C): SC: ERROR: %s\n", ctx.Pid, err.Error())
		ctx.cliConn.Close()
		if ctx.transState != 'I' {
			CleanupTrans(ctx.pBackConn.Conn)
		}
		if ctx.isGetBackend {
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return err
	}
	log.Printf("Client(%d, C): SC: Ready for query\n", ctx.Pid)
	err = sendPqReadyForQuery(ctx.cliConn, ctx.transState)
	if err != nil {
		log.Printf("Client(%d, C): SC: ERROR: %s\n", ctx.Pid, err.Error())
		ctx.cliConn.Close()
		if ctx.transState != 'I' {
			log.Printf("Client(%d, B): Cleanup backend(%d) transaction\n", ctx.Pid, ctx.pBackConn.Id)
			CleanupTrans(ctx.pBackConn.Conn)
		}
		if ctx.isGetBackend {
			log.Printf("Client(%d, B): release backend(%d)\n", ctx.Pid, ctx.pBackConn.Id)
			atomic.StoreInt32(&ctx.pBackConn.State, 0)
			ctx.isGetBackend = false
		}
		return err
	}
	return nil
}

func handleConnection(cliConn net.Conn) {
	var ctx ConnContext
	ctx.Init(cliConn)
	var err error
	var ret int

	ret, ctx.pool = handleAuth(cliConn, ctx.Pid)
	if ret != 0 {
		cliConn.Close()
		return
	}

	ctx.cachedPrepare.Init()

	defer ctx.cachedPrepare.Discard()

	for {
		err = ctx.recvRequest()
		if err != nil {
			log.Printf("Client(%d): Recv from client error: %s\n", ctx.Pid, err.Error())
			/* 做一些清理工作，把此后端连接上的事务回滚掉*/
			if ctx.transState != 'I' {
				CleanupTrans(ctx.pBackConn.Conn)
			}
			if ctx.isGetBackend {
				atomic.StoreInt32(&ctx.pBackConn.State, 0)
				ctx.isGetBackend = false
			}
			cliConn.Close()
			return
		}

		if ctx.recvBuf[0] == 'X' { /* 这是Terminate消息*/
			ctx.ProcessX()
			return
		} else if ctx.recvBuf[0] == 'Q' { /* 这是 Query 简单查询 */
			err = ctx.ProcessQ()
			if err != nil {
				return
			}
			continue
		} else if ctx.recvBuf[0] == 'P' || ctx.recvBuf[0] == 'B' || ctx.recvBuf[0] == 'D' {
			err = ctx.ProcessExtendedQuery()
			if err != nil {
				return
			}
			continue
		} else if ctx.recvBuf[0] == 'C' { /* 这是Close消息 */
			err = ctx.ProcessC()
			if err != nil {
				return
			}
			continue
		} else {
			log.Panicf("unknown message(%c)", ctx.msgList[0][0])
		}
		//log.Panicf("Client(%d): Unknown type(%c): %v", ctx.Pid, ctx.recvBuf[0], ctx.recvBuf[:ctx.recvLen])
	}
}

func checkPool() {
	var pool []*PgBackendConn
	var backConn *PgBackendConn
	for {
		time.Sleep(10 * time.Second)
		for _, pool = range g_backend_pool {
			for _, backConn = range pool {
				if atomic.CompareAndSwapInt32(&backConn.State, 0, 1) {
					backConn.CleanupNeedClosePrepare()
					backConn.State = 0
				}
			}
		}
	}
}

func startServer(listenAddr string) {
	var i int
	var dbConf *DbConfig
	var pool []*PgBackendConn
	var poolSize, _ = strconv.Atoi(g_proxyConf["default_pool_size"])
	var poolName string

	for _, dbConf = range g_backends {
		poolName = dbConf.User + "." + dbConf.Dbname
		pool = make([]*PgBackendConn, poolSize) /*user.dbname定义为一个pool*/
		g_backend_pool[poolName] = pool
		for i = 0; i < poolSize; i++ {
			conn, err := connectBackend(dbConf)
			if err != nil {
				return
			}
			pBackend := new(PgBackendConn)
			pBackend.Id = int32(i + 1)
			pBackend.Conn = conn
			pBackend.State = 0
			pBackend.nextPrepareId = 0
			pBackend.ReConnCnt = 0
			pBackend.dbConf = dbConf
			pool[i] = pBackend
		}
	}

	go checkPool()

	log.Printf("Starting server on %s ...\n", listenAddr)

	addr, _ := net.ResolveTCPAddr("tcp", listenAddr)

	listener, err := net.ListenTCP("tcp", addr)
	if err != nil {
		log.Printf("Could not listen on %s: %s", listenAddr, err.Error())
		return
	}

	for {
		con, err := listener.Accept()
		if err != nil {
			log.Printf("ERROR: failed to accepting a connection, %s", err.Error())
		}
		go handleConnection(con)
	}
}
